dev = false;
var CLIENT_ID = '';
var PROD_EXTENSION_ID = "cpcblbjkgjocjkbdngceojpghgppcmkc";
var DEV_EXTENSION_ID = "djdffnmficooopkdnaeocpihpanopejd";
var EXTENSION_ID = window.location.href.substr(19, 32);

switch (EXTENSION_ID) {
  case PROD_EXTENSION_ID: // Prod mode
    CLIENT_ID = "JCIF1PNNHFJEJ4UOFWYDXBDXJC0CYB0CGH5LCVDDMB2IBXAE";
    break;
  case DEV_EXTENSION_ID: // Dev mode (unpacked)
    dev = true;
    CLIENT_ID = "3L52KNWO3GCDGG32BO3DGJH0BMRVSJCIB5XYWO452N4S4FU1";
    console.log('You are now entering: DEVELOPMENT MODE');
    break;
  default: // Don't know!
    console.error('Unrecognized extension ID: ' + EXTENSION_ID);
}

// Lat/long query string that is only used when user only wants nearby checkins
var ll = '';

// When user only wants nearby checkins, any checkin more than this many
// meters away is considered "not nearby"
var NEARBY_THRESHOLD = 40000;

// Maximum # of notifications to show during one polling cycle
var MAX_NOTIFICATIONS = 3;

// Set up the periodic polling based on user preference (if any).
var currentInterval = 900000;
var interval = null;
updatePolling();

// Update location and poll on extension install / browser open.
prePoll();

/**
 * Cancels current polling interval (if any) and sets it to the new interval.
 *
 * This is also called when options.html changes the interval.
 */
function updatePolling() {
  getItem('interval', function(settings) {
    var newInterval = parseInt(settings['interval'] || '900000');
    if (newInterval != currentInterval) {
      currentInterval = newInterval;
      window.clearInterval(interval);
      interval = window.setInterval(prePoll, currentInterval);
    }
  });
}

// Also request user's own info each time browser starts
getMe();

/**
 * If the user only wants nearby checkins, figure out where 'nearby' is. Recent
 * checkins will include a 'distance' field if we pass a lat/long, which we can
 * check for nearbyness and filter.
 */
function prePoll() {
  getItem(null, function(settings) {
    if (!settings['token']) {
      startAuth();
      return;
    } else {
      if (settings['nearby']) {
        navigator.geolocation.getCurrentPosition(function(pos) {
          ll = '&ll=' + pos['coords']['latitude'] + ',' + pos['coords']['longitude'];
          poll(settings);
        });
      } else {
        ll = ''; // clear ll for later polls
        poll(settings);
      }
    }
  });
}

/**
 * Open a tab to commence authorization process.
 *
 * This will immediately close and begin polling if the user has already
 * granted access.
 */
function startAuth() {
  window.open( "https://foursquare.com/oauth2/authenticate?client_id=" +
      CLIENT_ID + "&response_type=token&redirect_uri=chrome-extension://" +
      EXTENSION_ID + "/oauth2callback.html");
}

/**
 * The core polling method, called every interval period.
 *
 * Initial Request:
 * - Request made to /checkins/recent, and resulting checkins compared against
 *   the checkin cache.
 * - If the cache does not know about the checkin user, that's a new friend -->
 *   add the checkin to the toNotify queue
 * - If the cache only knows about a different checkin ID, that's a new checkin
 *   --> add the checkin to the toNotify queue
 * - If the cache knows about the checkin ID, but has a different number of
 *   comments+photos, that's a new comment/photo --> fetch the full checkin
 *   (see below)
 * - If the response lists unread tray notifications, fetch those too.
 *
 * Followup Batch Request:
 * If there are any full checkins to fetch or tray notifications need to be
 *   fetched, they will be fetched in a batch request.
 * - Multi endpoint supports max of 5 batched requests, so reqs are trimmed
 * - Unread tray notifications above trayHighwater are added to toNotify queue
 * - Checkins that are fetched (with comments/photos included) are added to
 *   toNotify queue
 *
 * Notification Phase and Cleanup:
 * - toNotify is sorted by createdAt, newest first, and the first
 *   MAX_NOTIFICATIONS notifications are notified on.
 * - The checkin cache and highwater are updated, sound is played, ready for
 *   next poll()
 *
 * @param knownActive {boolean} Whether we know for a fact the user is not idle.
 */
function poll(settings) {
  getItem(null, function(settings) {
    var highwater = parseInt(settings['highwater'] || '0');

    var url = 'https://api.foursquare.com/v2/checkins/recent?afterTimestamp=' +
        highwater + ll;
    xhr(url, function(resp) {
      var fetchNotifications = resp['notifications'][0]['item']['unreadCount'];
      var checkinsToFetch = [];
      var toNotify = [];
      var cache = settings['cache'] || {};
      var notifyOnComments = settings['comments'];
      var checkins = resp['response']['recent'];

      var filter = settings['filter'];
      var filterFriends = filter ? (settings['filterFriends'] || []) : [];

      checkins.forEach(function(checkin) {
        var userid = checkin['user']['id'];

        // User only wants nearby checkins, and this isn't nearby.
        if (checkin['distance'] && checkin['distance'] > NEARBY_THRESHOLD) {
          return;
        }

        // User only wants checkins from certain users, and this isn't one.
        // The exception to this is friends who aren't in the cache.
        if (filter && filterFriends.indexOf(userid) < 0 && userid in cache) {
          return;
        }

        var commentsCount = 'comments' in checkin ? checkin['comments']['count'] : 0;
        var photosCount = 'count' in checkin['photos'] ? checkin['photos']['count'] : 0;
        var cpcount = commentsCount + photosCount;
        if (! (userid in cache)) {
          // New friend -- notify on it!
          cache[userid] = {
            checkinid: checkin['id'],
            cpcount: cpcount
          };

          // If filtering is on, new friends should be added to the filter,
          // otherwise you may never hear from them! (and that's just sad!)
          if (filter && filterFriends.indexOf(userid) < 0) {
            filterFriends.push(userid);
            setItem({
              filterFriends: filterFriends
            });
          }

          highwater = Math.max(highwater, checkin['createdAt']);
          (cpcount > 0 && notifyOnComments) ?
              checkinsToFetch.push(checkin['id']) : toNotify.push(checkin);
        } else if (cache[userid]['checkinid'] !== checkin['id']) {
          highwater = Math.max(highwater, checkin['createdAt']);
          // New checkin -- notify on it!
          (cpcount > 0 && notifyOnComments) ?
              checkinsToFetch.push(checkin['id']) : toNotify.push(checkin);
        } else if (cache[userid]['muted']) {
          // Checkin is old...and it's muted, so do nothing.
        } else if (cache[userid]['cpcount'] != cpcount && notifyOnComments) {
          // Checkin is old, but has new comment or photo, and we care about that
          checkinsToFetch.push(checkin['id']);
        } else {
          // Nothing has changed.
        }
      });

      // Store new filterFriends, just in case new users added to it.
      setItem({
        filterFriends: filterFriends
      });

      var reqs = [];
      if (fetchNotifications) {
        reqs.push('/updates/notifications');
      }
      for (var i = 0; i < checkinsToFetch.length; i++) {
        reqs.push('/checkins/' + checkinsToFetch[i]);
      }
      if (reqs.length === 0) {
        finish(toNotify, cache, highwater, settings['sound']);
      } else {
        var req = reqs.slice(0, 5).join(','); // Multi only supports 5 requests
        var url = 'https://api.foursquare.com/v2/multi?requests=' + req;
        xhr(url, function(resp) {
          var responses = resp['response']['responses'];
          for (var i = 0; i < responses.length; i++) {
            var response = responses[i]['response'];
            if ('notifications' in response) {
              // This is a tray notifications response
              var notifications = response['notifications']['items'];
              notifications.forEach(function(n) {
                // Only display notifications that are unread
                if (n['unread']  ) {
                  toNotify.push(n);
                  trayHighwater = n['createdAt'];
                }
              });
              continue;
            }
            var checkin = responses[i]['response']['checkin'];
            highwater = Math.max(highwater, checkin['createdAt']);

            checkin['comments']['items'].forEach(function(comment) {
              highwater = Math.max(highwater, comment['createdAt']);
            });

            checkin['photos']['items'].forEach(function(photo) {
              highwater = Math.max(highwater, photo['createdAt']);
            });

            cache[checkin['user']['id']] = {
              checkinid: checkin['id'],
              cpcount:
                  checkin['comments']['count'] + checkin['photos']['count']
            };
            toNotify.push(checkin);
          }
          finish(toNotify, cache, highwater, settings['sound']);
        });
      }
    });
  });
}

/**
 * Perform final step of polling -- update state, notify, and ding.
 */
function finish(toNotify, cache, highwater, sound) {
  setItem({
    cache: cache,
    highwater: highwater
  });
  toNotify.sort(byCreatedAt);
  toNotify.slice(0, MAX_NOTIFICATIONS).forEach(notify);
  ding(toNotify, sound);
}

/**
 * Play a sound if the user has the preference.
 */
var audio;
function ding(toNotify, sound) {
  if (toNotify.length && sound) {
    if (!audio) {
      audio = new Audio('sounds/ding.wav');    
    }
    audio.play();
  }
}

/**
 * Display a notification.
 */
function notify(obj) {
  var url = ('ids' in obj) ? 'trayNotification.html' : 'notification.html';
  url += '?' + encode(obj);

  // Track notifications
  if (!dev) { _gaq.push(['_trackEvent', 'notified']); }

  webkitNotifications.createHTMLNotification(url).show();
}

/**
 * Request the user's own user information (icon and ID) and store them.
 */
function getMe() {
  xhr('https://api.foursquare.com/v2/users/self', function(resp) {
    var self = resp['response']['user'];
    setItem({
      self_id: self['id'],
      self_pic: self['photo']
    });
  });
}